import { connect } from "react-redux";
import { isFunction } from "../helpers/checkType";
import { actions } from "./actions";

/**
 * 检查配置项
 * @param {Object} config
 */
function check(config) {
  const { component, state, actions: _actions } = config;
  if (!component)
    throw new Error("make sure `component` is a React.Component.");
  if (state && !isFunction(state))
    throw new Error("make sure `state` is a Function.");
  if (_actions && !isFunction(_actions))
    throw new Error("make sure `actions` is a Function.");
}

/**
 * 获取所有的actions
 *
 * @param {*} _actions
 */
function getActions(_actions) {
  const result = {};
  for (const key in _actions) {
    const action = _actions[key];
    result[key] = (...rest) => action(...rest);
  }

  return result;
}

/**
 * 创建container，包裹了connect函数
 *
 * @param {React.Component} component 被关联的React组件
 * @param {Object} opts 配置项
 * @param {String} opts.namespace 需要关联的namespace
 * @param {Function} opts.state state的过滤函数，同react-redux中connect函数的mapStateToProps。第一个参数，如果配置了`namespace`属性，则是`namespace`下的state
 * @param {Function} opts.actions actions过滤函数，类似react-redux中connect函数的mapDispatchToProps。第一个参数，如果配置了`namespace`属性，则是`namespace`下的actions
 * @param {Function} opts.mergeProps 同react-redux中connect函数的mergeProps
 * @param {Object} opts.options 同react-redux中connect函数的options
 *
 */
export default function createContainer(component, opts = {}) {
  check(Object.assign({}, { component }, opts));
  const {
    state: _state,
    actions: _actions,
    namespace,
    mergeProps,
    options
  } = opts;

  let mapStateToProps = null;
  let mapDispatchToProps = null;

  mapStateToProps = (originState, ownProps) => {
    let tempState = originState;
    if (namespace) tempState = tempState[namespace];
    if (isFunction(_state)) tempState = _state(tempState, ownProps);

    return tempState;
  };

  mapDispatchToProps = (dispatch, ownProps) => {
    let tempActions = {};

    for (const namespace in actions) {
      const actionByNamespace = actions[namespace];
      tempActions[namespace] = getActions(actionByNamespace);
      actions[namespace] = tempActions[namespace];
    }

    if (namespace) tempActions = tempActions[namespace];
    if (isFunction(_actions)) tempActions = _actions(tempActions, ownProps);

    return { actions: tempActions };
  };

  return connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    options
  )(component);
}
